#include "sound.h"
#include "text.h"
#include <OgreException.h>
using namespace audiere;

Sounder::Sounder()
{
	device = OpenDevice();
	parent = NULL;
	music_vol = 1.f;
	fx_vol = 1.f;
	streams.clear();
}

Sounder::~Sounder()
{
	streams.clear();
}

void Sounder::init(Base* par)
{
	parent = par;
	load_stream("hit", HIT_FX_FILE_NAME);
	load_stream("msg", MSG_FX_FILE_NAME);
	
	load_stream("eng1", ENG1_FX_FILE_NAME, true, 0.5f);
	load_stream("eng2", ENG2_FX_FILE_NAME, true, 0.5f);
	load_stream("eng3", ENG3_FX_FILE_NAME, true, 0.5f);

	load_stream("menu", MENU_MUS_FILE_NAME, false);
	load_stream("game", GAME_MUS_FILE_NAME, false);
	
	load_stream("water", WATER_FX_FILE_NAME, false);
	load_stream("bomb", BOMB_FX_FILE_NAME, false);
}

float Sounder::get_music_vol()
{
	return music_vol;
}

float Sounder::get_fx_vol()
{
	return fx_vol;
}
	
void Sounder::set_music_vol(float ratio)
{
	music_vol = ratio;
	update_all_vol(false);
}

void Sounder::set_fx_vol(float ratio)
{
	fx_vol = ratio;
	update_all_vol(true);
}

Sounder::Stream::Stream() {}

Sounder::Stream::Stream(Sounder* par,
			   std::string dir,
			   bool is_fx,
			   float vol_mask,
			   float pitch_mask,
			   float pan_offset):
	is_fx(is_fx),
	vol_mask(vol_mask),
	pitch_mask(pitch_mask),
	pan_offset(pan_offset)
{
	OutputStreamPtr tmp(OpenSound(par->get_device(), dir.c_str(), false));
	stream = tmp;
	stream->setPan(pan_offset);
	stream->setVolume(vol_mask);
	stream->setPitchShift(pitch_mask);
}

	
AudioDevicePtr Sounder::get_device()
{
	return device;
}

void Sounder::load_stream(std::string name, std::string dir,
					 bool is_fx,
		             float vol_mask,
					 float pitch_mask,
					 float pan_offset)
{
	if (device)
	{
		if (streams.count(name))
			throw Ogre::Exception(6, "Stream name <" + name + "> already exists", "sound.cpp, Sounder::load_stream");
		streams[name] = Sounder::Stream(this, dir, is_fx, vol_mask, pitch_mask, pan_offset);
	}
}

void Sounder::remove_stream(std::string name)
{
	if (device)
	{
		std::map<std::string, Sounder::Stream>::iterator it = streams.find(name);
		if (it != streams.end())
			streams.erase(it);
	}
}

void Sounder::remove_all_stream()
{
	streams.clear();
}

void Sounder::play_once(std::string name, float from, float to)
{
	if (device)
	{
		Sounder::Stream& q = streams[name];
		OutputStreamPtr& p = q.stream;
		p->setVolume(q.vol_mask * (q.is_fx ? fx_vol : music_vol));
		p->setRepeat(false);
		p->setPosition((int)(from * p->getLength()));
		p->play();
	}
}

void Sounder::play_repeat(std::string name, float from, float to)
{
	if (device)
	{
		Sounder::Stream& q = streams[name];
		OutputStreamPtr& p = q.stream;
		p->setVolume(q.vol_mask * (q.is_fx ? fx_vol : music_vol));
		p->setRepeat(true);
		//p->setPosition((int)(from * p->getLength()));
		p->play();
	}
}

void Sounder::stop(std::string name)
{
	if (device)
	{
		Sounder::Stream& q = streams[name];
		OutputStreamPtr& p = q.stream;
		p->stop();
	}
}

void Sounder::stop_all()
{
	if (device)
	{
		for (std::map<std::string, Sounder::Stream>::iterator it = streams.begin();
			 it != streams.end();
			 ++it)
			 it->second.stream->stop();
	}
}
	
void Sounder::set_pitch(std::string name, float pitch)
{
	if (device)
	{
		Sounder::Stream& q = streams[name];
		OutputStreamPtr& p = q.stream;
		p->setPitchShift(q.pitch_mask * pitch);
	}
}

void Sounder::set_pan(std::string name, float pan)
{
	if (device)
	{
		Sounder::Stream& q = streams[name];
		OutputStreamPtr& p = q.stream;
		p->setPan(q.pan_offset+pan);
	}
}

void Sounder::update_all_vol(bool is_fx)
{
	if (device)
	{
		for (std::map<std::string, Sounder::Stream>::iterator it = streams.begin();
			 it != streams.end();
			 ++it)
		{
			it->second.stream->setVolume(it->second.vol_mask * (it->second.is_fx ?
				fx_vol : music_vol));
		}
	}
}